// $URL: http://mingw-lib.googlecode.com/svn/trunk/working/avcodec_to_widget_10/t_box_player_ctx.h $
// $Rev: 351 $
// $Author: akio.miyoshi $
// $Date:: 2010-08-03 02:54:21 +0000#$

#ifndef T_BOX_PLAYER_H
#define T_BOX_PLAYER_H

#include "stable.h"
#include "t_box.h"
#include "t_av_packet.h"
#include "t_generator.h" //==> t_box_audio.h
#include "t_box_bar.h"
#include "input/t_box_input_sequence.h"
#include "t_box_stream.h"

class T_Box_Stream_Main : public T_Box_Stream
{
    Q_OBJECT
public:
    explicit T_Box_Stream_Main(T_Box_Core *a_core)
        : T_Box_Stream(a_core)
    {
        this->openAudio();
        this->openVideo();
    }
    //~T_Box_Stream_Main();
    //T_Box_Core *core();
    //bool openAudio();
    //bool openVideo();
    //T_AV_Packet *readPacket();
protected:
    void run()
    {
        for(;;)
        {
            msleep(1);
            if(this->closing())
            {
                break;
            }
            T_AV_Packet *v_packet = NULL;
            {
                v_packet = this->readPacket();
                if(!v_packet)
                {
                    this->core()->seekManager()->registerTiming(LONG_LONG_MAX);
                    break;
                }
                this->core()->seekManager()->registerTiming(v_packet->timing());
                delete v_packet;
            }
        }
    }
};

struct T_Box_Stream_Info
{
    bool isValid;
    int stream_index;
    AVCodecContext *codec_ctx;
    AVCodec *codec;
    AVStream *stream;
    T_AV_Packet_Queue packet_queue;
    explicit T_Box_Stream_Info(T_Box_Player_Context *a_player_ctx, AVMediaType a_media_type);
};

class T_Box_Player_Context : public QObject
{
    Q_OBJECT
public:
    T_Box_Input_Sequence *m_box_input;
    AVFormatContext *m_format_ctx;
    T_Box_Core m_core;
    T_Box_Stream_Info m_audio;
    T_Box_Stream_Info m_video;
    //T_Stopwatch m_stopwatch;
    QAudioOutput *m_audioOutput;
    T_Generator *m_generator;
    T_VideoProgressBar *m_seek_bar;
    T_BufferProgressBar *m_buffering_bar;
    T_AVPicture m_video_decode_buff; //FIXME
    T_Box_Stream_Main m_stream_main;
public:
    explicit T_Box_Player_Context(T_Box_Input_Sequence *a_box_input, AVFormatContext *a_format_ctx);
    ~T_Box_Player_Context();
    void setAudioOutput(QAudioOutput *a_audioOutput)
    {
        m_audioOutput = a_audioOutput;
    }
    qint64 duration()
    {
        return  ((qint64)1000) * this->m_format_ctx->duration / AV_TIME_BASE;
    }
    QString durationToString(const QString &a_format)
    {
        QTime v_duration_clock(0, 0, 0, 0);
        v_duration_clock = v_duration_clock.addMSecs(this->duration());
        return v_duration_clock.toString(a_format);
    }
    bool needBuffering()
    {
#if USE_DECODE_THREAD
         QSharedPointer<T_AV_Packet> v_head = m_video.packet_queue.head();
        if(v_head && v_head->frameNo()<=T_Box::PLAYER_AHEAD_IMAGE && v_head->isDecoded())
        {
            //return false;
        }
        else
        {
            static bool v_emergency = false;
            if(v_emergency)
            {
                if(m_video.packet_queue.decodedCount(T_Box::PLAYER_IMAGE_STOCK)<T_Box::PLAYER_IMAGE_STOCK)
                {
                    return true;
                }
            }
            v_emergency = false;
            if(m_video.packet_queue.decodedCount(T_Box::PLAYER_AHEAD_IMAGE)<T_Box::PLAYER_AHEAD_IMAGE)
            {
                v_emergency = true;
                return true;
            }
        }
#endif
        if(m_video.packet_queue.duration(this->timeline()->elapsed())<T_Box::PLAYER_BUFFER_TIME)
        {
            return true;
        }
        return false;
    }
    T_Box_Seek_Manager *seekManager()
    {
        return m_core.seekManager();
    }
    T_Stopwatch *timeline()
    {
        return m_core.timeline();
    }
    void start();
    void finish();
    bool handleSeek(bool decodeVideo = false);
protected:
    qint64 seek(qint64 a_msec, bool decodeVideo = false);
    T_AV_Packet *readPacket();
    T_AV_Packet *enqueuePacket(bool decodeVideo = false);
protected:
    friend class T_Box_Player_Packet_Thread;
    friend class T_Box_Player_Decode_Thread;
    class T_Box_Player_Packet_Thread *m_packet_thread;
    class T_Box_Player_Decode_Thread *m_decode_thread;
};

class T_Box_Player_Packet_Thread : public T_Box_Thread
{
public:
    explicit T_Box_Player_Packet_Thread(T_Box_Player_Context *a_player_ctx)
        : m_player_ctx(a_player_ctx)
    {
    }
protected:
    virtual void run();
    T_Box_Player_Context *m_player_ctx;
};

class T_Box_Player_Decode_Thread : public T_Box_Thread
{
public:
    explicit T_Box_Player_Decode_Thread(T_Box_Player_Context *a_player_ctx)
        : m_player_ctx(a_player_ctx)
    {
    }
protected:
    virtual void run();
    T_Box_Player_Context *m_player_ctx;
};

#endif // T_BOX_PLAYER_H
